import asyncio
import json
import sys
from datetime import datetime
from typing import Optional
from mcp.client.stdio import stdio_client
from mcp import ClientSession, StdioServerParameters
from contextlib import AsyncExitStack
from dotenv import load_dotenv
import os
from openai import OpenAI

# 加载 .env 文件，确保 API Key 受到保护
load_dotenv(override=True)

class MCPClient:

    logFilePath = "d:/weather_log.txt"

    def __init__(self):

        """初始化 MCP 客户端"""
        self.openai_api_key = os.getenv("OPENAI_API_KEY")  # 读取 OpenAI API Key
        self.base_url = os.getenv("BASE_URL")  # 读取 BASE YRL
        self.model = os.getenv("MODEL")  # 读取 model


        if not self.openai_api_key:
            raise ValueError("❌ 未找到 OpenAI API Key，请在 .env 文件中设置OPENAI_API_KEY")

        self.client = OpenAI(api_key=self.openai_api_key, base_url=self.base_url)
        #self.session = None
        self.session:Optional[ClientSession] = None
        self.exit_stack = AsyncExitStack()

    async def connect_to_mock_server(self,server_script_path:str):
        """模拟 MCP 服务器的连接(暂不连接真实服务器)"""
        #print("✅ MCP 客户端已初始化,但未连接到服务器")
        is_python = server_script_path.endswith(".py")
        is_js = server_script_path.endswith(".js")

        if not (is_python or is_js):
            raise ValueError("服务器脚本必须是 .py 或 .js文件")

        command = "python" if is_python else "node"
        server_params = StdioServerParameters(
            command=command,
            args=[server_script_path],
            env=None
        )

        stdio_transport = await self.exit_stack.enter_async_context(stdio_client(server_params))
        self.stdio,self.write = stdio_transport
        self.session = await self.exit_stack.enter_async_context(ClientSession(self.stdio,self.write))

        await self.session.initialize()
        response = await self.session.list_tools()
        tools = response.tools

        print(f"\n✅ MCP 客户端已初始化,已连接到服务器,可用工具：",[tool.name for tool in tools])

    async def process_query(self, query: str) -> str:
        """调用 OpenAI API 处理用户查询"""
        messages = [{"role": "user", "content": query}]
        response = await self.session.list_tools()

        available_tools = [{
            "type": "function",
            "function": {
                "name": tool.name,
                "description": tool.description,
                "input_schema": tool.inputSchema
            }
        } for tool in response.tools]

        # 调用 OpenAI API
        response = self.client.chat.completions.create(
            model=self.model,
            messages=messages,
            tools=available_tools
        )

        content = response.choices[0]


        if content.finish_reason == "tool_calls":
            print(f"\n\n{content.message.tool_calls}\n\n")
            messages.append(content.message.model_dump())
            for i in range(len(content.message.tool_calls)):
                tool_call = content.message.tool_calls[i]
                tool_name = tool_call.function.name
                tool_args = json.loads(tool_call.function.arguments)

                result = await self.session.call_tool(tool_name, tool_args)
                self.writeLog("client===  call_tool: " + tool_name + "  args: " + json.dumps(tool_args) + "  result: " + result.content[0].text + "\n")

                print(f"\n\n[Calling tool {tool_name} with args {tool_args}]\n\n")

                if isinstance(result.content,list):
                    content = result.content[0].text
                elif isinstance(result.content,str):
                    content = result.content
                else:
                    content = result

                messages.append({
                    "tool_call_id": tool_call.id,
                    "role": "tool",
                    "content": result.content[0].text
                })

            response = self.client.chat.completions.create(
                model=self.model,
                messages=messages
            )
            return response.choices[0].message.content

        return content.message.content

    async def chat_loop(self):
        """运行交互式聊天循环"""
        print("\nMCP 客户端已启动!输入 'quit' 退出")
        while True:
            try:
                query = input("\n你: ").strip()
                if query.lower() == 'quit'  or query.lower() == 'bye':
                    break

                response = await self.process_query(query)
                print(f"\n🤖 OpenAI:{response}")
            except Exception as e:
                print(f"\n⚠️发生错误: {str(e)}")

    async def cleanup(self):
        """清理资源"""
        await self.exit_stack.aclose()

    def writeLog(self,message: str):
        timestr = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
        with open(MCPClient.logFilePath, 'a', encoding='utf-8') as file:
            file.write(timestr + ":" + message + '\n')

async def main():
    if len(sys.argv) < 2:
        print("Usage: python client.py <path_to_server_script>")
        sys.exit(1)

    client = MCPClient()
    try:
        await client.connect_to_mock_server(sys.argv[1])
        await client.chat_loop()
    finally:
        await client.cleanup()



if __name__ == "__main__":
    asyncio.run(main())
